#include "stdafx.h"
#include <XFont.h>
#include <OpenGL\glew.h>

XFont::XFont()
{
	ID = 0;

	VertexBuffer = 0;
	IndexBuffer = NULL;

	Space = 0;
	NewLine = 0;
	LineHeight = 0;
}

XFont::~XFont()
{
	Unload();
}

void XFont::_freeBuffer()
{
	if(VertexBuffer != 0)
		glDeleteBuffers(1, &VertexBuffer);
	if(IndexBuffer != NULL)
	{
		glDeleteBuffers(256, IndexBuffer);
		delete[] IndexBuffer;
	}

	VertexBuffer = 0;
	IndexBuffer = NULL;
}

void XFont::_freeTexture()
{
	if(ID != 0)
		glDeleteTextures(1, &ID);

	ID = 0;
}

void XFont::_initBuffers(XRectangle* clips, int num)
{
	_freeBuffer();

	IndexBuffer = new unsigned int [num];
	float vTop, vBottom, vLeft, vRight;
	float tTop, tBottom, tLeft, tRight;

	glGenBuffers(1, &VertexBuffer);
	glGenBuffers(num, IndexBuffer);

	XVertexData* vData = new XVertexData[num * 4];
	unsigned int iData[4];

	for(int i=0; i<num; i++)
	{
		vTop = 0;
		vBottom = clips[i].H;
		vLeft = 0;
		vRight = clips[i].W;

		tTop = clips[i].Y/Height;
		tBottom = (clips[i].Y + clips[i].H)/Height;
		tLeft = clips[i].X/Width;
		tRight = (clips[i].X + clips[i].W)/Width;

		iData[0] = i * 4 + 0;
		iData[1] = i * 4 + 1;
		iData[2] = i * 4 + 2;
		iData[3] = i * 4 + 3;
		
		vData[iData[0]].Position.X = vLeft;
		vData[iData[0]].Position.Y = vTop;
		vData[iData[1]].Position.X = vRight;
		vData[iData[1]].Position.Y = vTop;
		vData[iData[2]].Position.X = vRight;
		vData[iData[2]].Position.Y = vBottom;
		vData[iData[3]].Position.X = vLeft;
		vData[iData[3]].Position.Y = vBottom;
		
		vData[iData[0]].TextureCoord.X = tLeft;
		vData[iData[0]].TextureCoord.Y = tTop;
		vData[iData[1]].TextureCoord.X = tRight;
		vData[iData[1]].TextureCoord.Y = tTop;
		vData[iData[2]].TextureCoord.X = tRight;
		vData[iData[2]].TextureCoord.Y = tBottom;
		vData[iData[3]].TextureCoord.X = tLeft;
		vData[iData[3]].TextureCoord.Y = tBottom;

		glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, IndexBuffer[i]);
		glBufferData(GL_ELEMENT_ARRAY_BUFFER, 4 * sizeof(unsigned int), iData, GL_DYNAMIC_DRAW);
	}

	glBindBuffer(GL_ARRAY_BUFFER, VertexBuffer);
	glBufferData(GL_ARRAY_BUFFER, 4 * sizeof(XVertexData) * num, vData, GL_STATIC_DRAW);

	glBindBuffer(GL_ARRAY_BUFFER, NULL);
	glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, NULL);

	delete[] vData;
}

void XFont::_initTexture(unsigned char* pixels, int width, int height)
{
	_freeTexture();

	glGenTextures(1, &ID);
	glBindTexture(GL_TEXTURE_2D, ID);
	glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, width, height, 0, GL_ALPHA, GL_UNSIGNED_BYTE, pixels);
	glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
	glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
	glBindTexture(GL_TEXTURE_2D, NULL);

	Width = width;
	Height = height;
}

void XFont::Load(std::string path, int size)
{
	Unload();

	FT_Init_FreeType( &Library);

	unsigned int cellHeight = 0;
	unsigned int cellWidth = 0; 
	int maxBearing = 0; 
	int minHang = 0;

	unsigned char** Pixels = new unsigned char*[256]; 
	unsigned int* Width = new unsigned int[256];
	unsigned int* Height = new unsigned int[256];

	FT_Glyph_Metrics metrices[ 256 ];
	FT_Face face = NULL;
	FT_New_Face(Library, path.c_str(), 0, &face);
	FT_Set_Pixel_Sizes(face, 0, size);

	for(int i=0; i<256; i++)
	{
		FT_Load_Char(face, i, FT_LOAD_RENDER);
		metrices[i] = face->glyph->metrics;

		Pixels[i] = new unsigned char[face->glyph->bitmap.width * face->glyph->bitmap.rows];

		for(int j=0; j<face->glyph->bitmap.width * face->glyph->bitmap.rows; j++)
		{
			Pixels[i][j] = 0;
		}

		Width[i] = face->glyph->bitmap.width;
		Height[i] = face->glyph->bitmap.rows;
		memcpy(Pixels[i], face->glyph->bitmap.buffer, face->glyph->bitmap.width * face->glyph->bitmap.rows);

		if( metrices[ i ].horiBearingY / 64 > maxBearing )
		{ 
			maxBearing = metrices[i].horiBearingY / 64;
		} 

		if( metrices[i].width / 64 > cellWidth)
		{ 
			cellWidth = metrices[i].width / 64; 
		}

		int glyphHang = ( metrices[ i ].horiBearingY - metrices[ i ].height ) / 64; 

		if( glyphHang < minHang )
		{ 
			minHang = glyphHang; 
		} 
	}

	cellHeight = maxBearing - minHang;


	unsigned char* FontPixels = new unsigned char[cellWidth*16 * cellHeight*16];

	for(int i=0; i<cellWidth*16 * cellHeight*16; i++)
	{
		FontPixels[i] = 0;
	}

	unsigned int PixelHeight = cellHeight*16;
	unsigned int PixelWidth = cellWidth*16;
	Clips = new XRectangle[256];

	unsigned int currentChar = 0;

	int bX = 0;
	int bY = 0;

	for(int rows = 0; rows < 16; rows++)
	{
		for(int columns = 0; columns < 16; columns++)
		{
			bX = cellWidth * columns;
			bY = cellHeight * rows;

			Clips[currentChar].X = bX;
			Clips[currentChar].Y = bY;
			Clips[currentChar].W = metrices[currentChar].width/64;
			Clips[currentChar].H = cellHeight;

			
			for(int i=0; i<Height[currentChar]; i++)
			{
				memcpy(&FontPixels[ (i+bY + maxBearing - metrices[ currentChar ].horiBearingY / 64) * PixelWidth + bX], &Pixels[currentChar][i * Width[currentChar]], Width[currentChar]);
			}
	
			currentChar++;
		}
	}

	_initTexture(FontPixels, PixelWidth, PixelHeight);
	_initBuffers(Clips, 256);

	Space = cellWidth / 2;
	NewLine = cellHeight;
	LineHeight = maxBearing - minHang+size/10;

	FT_Done_Face( face );

    FT_Done_FreeType(Library);

}

void XFont::Unload()
{
	_freeBuffer();
	_freeTexture();
}